import { RepoLink, Link, Warning } from '@brillout/docpress'
import { UiFrameworkExtension, ConfigSpec } from '../../components'

<ConfigSpec
  env="client (server can import but not call it)"
  global={null}
/>

The `navigate('/some/url')` function enables you to programmatically switch pages without requiring the user to click a link.

For example, to redirect the user after a successful form submission:

```tsx
import { navigate } from 'vike/client/router'

function Form() {
  return <form onSubmit={onSubmit}>{/* ... */}</form>
}

async function onSubmit() {
  const navigationPromise = navigate('/form/success')
  console.log("The URL changed but the new page hasn't rendered yet.")
  await navigationPromise
  console.log('The new page has finished rendering.')
}
```

> If you want to redirect the user before the page has fully rendered (e.g. redirecting a non-authenticated user), then use <Link href='/redirect'>`throw redirect()`</Link> instead. See: <Link href="/abort#throw-redirect-vs-throw-render-vs-navigate" doNotInferSectionTitle={true} noBreadcrumb />.

> To navigate back or forward in the user's browser history, use the [History API](https://developer.mozilla.org/en-US/docs/Web/API/History) instead:
>  - To go back, use [`window.history.back()`](https://developer.mozilla.org/en-US/docs/Web/API/History/back).
>  - To go forward, use [`window.history.forward()`](https://developer.mozilla.org/en-US/docs/Web/API/History/forward).

> For reloading the current page, use <Link href="/reload">`reload()`</Link> instead.


## Options

 - `navigate('/some-url', { keepScrollPosition: true })`: Don't scroll to the top of the page, preserve the scroll position instead. See also:
   - <Link href="/keepScrollPosition" />
   - <Link href="/clientRouting#settings">`<a href="/some-url" keep-scroll-position />`</Link>.
 - `navigate('/some-url', { overwriteLastHistoryEntry: true })`: Let the new URL replace the current URL in the browser history (instead of creating a new entry in the browser history). This effectively removes the current URL from the browser history. (Technically speaking: tell Vike to use [`history.replaceState()`](https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState) instead of [`history.pushState`](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState)..)
 - `navigate('/some-url', { pageContext })`: Pass extra <Link href="/pageContext">`pageContext`</Link> values to the next page.


## `history.pushState()`

If you want to change the URL completely independently of Vike then use [`history.pushState()`](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState) instead of `navigate()`.

```ts
// Somewhere in your client-side code
window.history.pushState(null, '', '/some-url')
```

You can then implement your navigation handling by listening to the [`popstate` event](https://developer.mozilla.org/en-US/docs/Web/API/Window/popstate_event).

<Warning>**You must handle the `popstate` event**, otherwise you'll break the browser's back- and forward history button.</Warning>

```ts
window.addEventListener('popstate', () => {
  // Vike sets triggeredBy to 'vike' | 'browser' | 'user'
  // https://vike.dev/navigate#history-pushstate
  const { triggeredBy } = window.history.state?.vike

  // Navigation triggered by Vike or the browser
  if (triggeredBy === 'vike' || triggeredBy === 'browser') {
    // Abort: let Vike handle the navigation
    return
  }

  // Navigation triggered by our history.pushState() call
  if (triggeredBy === 'user') {
    // To Do: implement back- and forward navigation
  }
})
```


## Without `vike-{react,vue,solid}`

If you don't use a <UiFrameworkExtension /> and if you use <Link text="Server Routing" href="/server-routing" /> then use `window.location.href = '/some/url'` instead of `navigate()` (because `navigate()` requires <Link text="Client Routing" href="/client-routing" />).

> The <UiFrameworkExtension plural noLink /> use Client Routing.


## See also

- <Link href="/reload" />
- <Link href="/redirect" />
- <Link href="/redirects" />
- <Link href="/abort#throw-redirect-vs-throw-render-vs-navigate" doNotInferSectionTitle={true} />
